﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WarriorRush.GameDynamics.Characters;
using WarriorRush.GameDynamics.Utilities;
using WarriorRush.UserInterface;
using Microsoft.Xna.Framework;

namespace WarriorRush.GameDynamics
{
    public class BattleManager
    {

        public Arena Arena;
        
        public CharacterManager CharacterManager;
        public WarriorCodex CharacterSetup;
        public SelectionManager SelectionManager;
        public SetupManager SetupManager;

        public FrameState FrameState;
        public BattleState BattleState;


        public void Init(WarriorCodex setup,  SelectionManager selectManager, SetupManager setupManager)
        {
            CharacterSetup = setup;
            SelectionManager = selectManager;
            SetupManager = setupManager;
        }

        public BattleManager()
        {
            Arena = new Arena();
            BattleState = new BattleState();
            BattleState.CurrentPhase = Phases.ArenaSetup;
            FrameState = new FrameState();
        }


        public void Start()
        {
            FrameState.Reset();
        }
        public void Update()
        {
            
            switch (BattleState.CurrentPhase)
            {
                case Phases.ArenaSetup:
            
                var selection = SelectionManager
                     .GetCurrentSelections(BattleState.CurrentPlayer, SelectionType.Setup)
                     .Squares
                     .Where(f => f.IsSelected).FirstOrDefault();
                BattleState.CurrentSquare = selection != null ? selection.Square : null;

                if (FrameState.IsDoneHit)
                {
                    FrameState.IsDoneHit = false;
                    if (BattleState.CurrentPlayer == Player.one)
                    {
                        SwitchPlayer();
                        SelectionManager.AddSelectionOptions(Player.two, SelectionType.Setup, SetupManager.GetCurrentSquares());
                        FrameState.CurrentSquare = null;
                    }
                    else
                    {
                        SwitchPlayer();
                        StartPlayerTurn();
                        BattleState.CurrentRusher = Player.one;
                    }
                }
                    
                break;

            case Phases.RushSelection:
                HandleRush();
                break;
            }
        }

        public SelectionHandler GetRushTargets(CharacterClass rusher)
        {
            
            return new SelectionHandler()
            {
                Squares = Arena
                            .GetTargetedSpaces(rusher.Square, rusher.GetRushRange(), true)
                            .Select(f => new Selectable() { Square = f })
                            .ToList(),
                SelectType = HighlightType.Targetable,
                MaxSelections = 1,
                IsReplacedSelection = true
            };
        }
        public void SwitchPlayer()
        {
            BattleState.CurrentSquare = null;
            BattleState.CurrentPlayer = BattleState.OtherPlayer;
            SetupManager.CurrentPlayer = BattleState.CurrentPlayer;
        }

        public void StartPlayerTurn()
        {

           
            BattleState.CurrentPhase = Phases.RushSelection;
            BattleState.CurrentSelection = SelectionType.Rusher;
           
        }



        public SelectionHandler InitiateRush(CharacterClass rusher, CharacterClass target)
        {

            if (rusher.OffensiveAbility.RequiresAddtionalTarget)
                return rusher.OffensiveAbility.GetAllTargets(Arena, target.Square);

            return null;
                    
            
        }

        public SelectionHandler CarryOutRush(CharacterClass rusher, CharacterClass target, List<CharacterClass> additionalTargets)
        {
            rusher.Rush(target, Arena,  additionalTargets);
            if (target.DefensiveAbility.RequiresAddtionalTarget)
                return target.DefensiveAbility.GetAllTargets(Arena, rusher.Square);
            return null;
        }

        public bool FinalAction(CharacterClass rusher, CharacterClass target, List<CharacterClass> additionalTargets)
        {
            if (target.DefensiveAbility.RequiresAddtionalTarget  && target.Stats.Health > 0)
                target.DefensiveAbility.Execute(rusher, Arena, additionalTargets);
           

            return true;

        }

        public void HandleRush()
        {
            switch (BattleState.RushPhase)
            {
                case RushStage.Start:
                    BattleState.RushPhase = RushStage.Start;
                    if (FrameState.IsMainTargetChosen)
                    {
                        var square = SelectionManager
                                .GetCurrentSelections(BattleState.CurrentPlayer, SelectionType.Rusher)
                                .GetSelectedSquares()
                                .FirstOrDefault();
                        BattleState.Rusher = square != null ? square.Character : null;

                        SelectionManager.AddSelectionOptions(BattleState.CurrentPlayer, SelectionType.RushTarget, GetRushTargets(BattleState.Rusher));


                    }
                    if (FrameState.IsSecondaryTargetChosen)
                    {
                        var square = SelectionManager
                              .GetCurrentSelections(BattleState.CurrentPlayer, SelectionType.RushTarget)
                              .GetSelectedSquares()
                              .FirstOrDefault();

                        BattleState.RushTarget = square != null ? square.Character : null;
                    }

                    if (FrameState.IsDoneHit && BattleState.RushTarget != null && BattleState.Rusher != null)
                    {
                        FrameState.IsDoneHit = false;
                        var additionalTargets = InitiateRush(BattleState.Rusher, BattleState.RushTarget);
                        SelectionManager.AddSelectionOptions(BattleState.CurrentPlayer, SelectionType.AbilityTarget, additionalTargets);
                        goto case (RushStage.AdditionalAttackTargetRequired);
                    }
                    break;
                case RushStage.AdditionalAttackTargetRequired:
                    BattleState.RushPhase = RushStage.AdditionalAttackTargetRequired;
                    BattleState.CurrentSelection = SelectionType.AbilityTarget;
                    if (BattleState.Rusher.OffensiveAbility.RequiresAddtionalTarget)
                    {
                        if (FrameState.IsDoneHit && SelectionManager.GetCurrentSelections(BattleState.CurrentPlayer, SelectionType.AbilityTarget).GetSelectedSquares().Any())
                        {
                           FrameState.IsDoneHit = false;
                            goto case RushStage.Attack;
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                       
                        goto case RushStage.Attack;

                    }

                    
                case RushStage.Attack:
                    BattleState.RushPhase = RushStage.Attack;
                    var addTargets = SelectionManager.GetCurrentSelections(BattleState.CurrentPlayer, SelectionType.AbilityTarget);
                    var targetActions = CarryOutRush(
                               BattleState.Rusher,
                               BattleState.RushTarget,
                               addTargets != null && addTargets.Squares != null && addTargets.Squares.Any()?
                               addTargets.GetSelectedSquares().Select(f=>f.Character).ToList() : null
                           );
                    SelectionManager.AddSelectionOptions(
                                               BattleState.OtherPlayer,
                                               SelectionType.AbilityTarget,
                                               targetActions);
                    ClearDeadInBack();
                    BattleState.RushDeathRoster = Arena.GetDeadCharacters((int)BattleState.CurrentPlayer + 1);
                    BattleState.DefenderDeathRoster = Arena.GetDeadCharacters((int)BattleState.OtherPlayer + 1);
                    

                    BattleState.IsDefenseReplacementRequired = 
                        HighlightPossibleReplacements(false, BattleState.OtherPlayer) != null;
                    
                    
                    if(HighlightPossibleReplacements(true,BattleState.CurrentPlayer) != null)
                        goto case RushStage.OffenseReplacementRequired;

                    goto case RushStage.Defense;


                
                case RushStage.OffenseReplacementRequired:
                    BattleState.RushPhase = RushStage.OffenseReplacementRequired;
                    BattleState.CurrentSelection = SelectionType.Replacement;
                    if (BattleState.RushDeathRoster.Any())
                    {
                        if (FrameState.IsDoneHit)
                        {
                            FrameState.IsDoneHit =false;
                            if(ReplaceCharacter(BattleState.CurrentPlayer,BattleState.RushDeathRoster))

                                goto case RushStage.Defense;
                        }
                        break;
                    }
                    else
                    {
                        goto case RushStage.Defense;
                    }
                case RushStage.Defense :
                    BattleState.RushPhase = RushStage.Defense;
                        SwitchPlayer();       
                    goto case RushStage.AdditionalDefenseTargetRequired;
                case RushStage.AdditionalDefenseTargetRequired:

                    BattleState.RushPhase = RushStage.AdditionalDefenseTargetRequired;
                    BattleState.CurrentSelection = SelectionType.AbilityTarget;
                  

                    if (BattleState.RushTarget.DefensiveAbility.RequiresAddtionalTarget && !BattleState.RushTarget.IsDead)
                    {
                        var defensiveTarget =SelectionManager.GetCurrentSelections(BattleState.CurrentPlayer, SelectionType.AbilityTarget).GetSelectedSquares();
                        
                        if (FrameState.IsDoneHit && defensiveTarget.Any())
                        {
                            FrameState.IsDoneHit = false;
                           FinalAction(BattleState.Rusher,BattleState.RushTarget,defensiveTarget.Select(f => f.Character)
                            .ToList());
                            goto case RushStage.DefenseReplacementRequired;
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        FinalAction(BattleState.Rusher, BattleState.RushTarget, null);
                        goto case RushStage.DefenseReplacementRequired;

                    }

                    
                case RushStage.DefenseReplacementRequired:
                    if (!BattleState.IsDefenseReplacementRequired)
                        goto case RushStage.Done;
                    BattleState.RushPhase = RushStage.DefenseReplacementRequired;
                    BattleState.CurrentSelection = SelectionType.Replacement;
                    if (BattleState.DefenderDeathRoster.Any())
                    {
                        if (FrameState.IsDoneHit)
                        {
                            FrameState.IsDoneHit = false;
                            if(ReplaceCharacter(BattleState.CurrentPlayer, BattleState.DefenderDeathRoster))
                                goto case RushStage.Done;
                        }
                        break;
                    }
                    else
                    {
                        goto case RushStage.Done;
                    }
                case RushStage.Done:

                    StartNewTurn();
                    break;


            }
        }
        
        private bool ReplaceCharacter(Player player, List<CharacterClass> deathRoster)
        {
            deathRoster.RemoveAll(f => !Arena.CheckIfCharacterHasReplacement(f));
            if(!deathRoster.Any())
                return true;
            var character = deathRoster.First();
            var replacement =
                             SelectionManager
                                 .GetCurrentSelections(player, SelectionType.Replacement)
                                 .GetSelectedSquares();

            if (replacement != null && replacement.Count > 0)
            {
                replacement.First().MoveCharacterToSquare(character.Square);
                deathRoster.RemoveAt(0);
                if (deathRoster.Any())
                {
                    
                    return HighlightPossibleReplacements(player == BattleState.CurrentRusher, player) == null;
                    
                }
                return true;
            }
            else
            {
                deathRoster.RemoveAt(0); 
            }
           

            return false;
        }
        private CharacterClass HighlightPossibleReplacements(bool IsRusher, Player player)
        {
            var deathRoster = IsRusher ? BattleState.RushDeathRoster : BattleState.DefenderDeathRoster;
           
            if (deathRoster.Any())
            {
                foreach (var deadWarrior in deathRoster)
                {
                    if(CheckCharacterLoss(player, deadWarrior))
                        return deadWarrior;
                   
                }
            }
            return null ;
        }

        private bool CheckCharacterLoss(Player player, CharacterClass character )
        {
            if (character.IsDead)
            {
                
                var replacements =  Arena.GetReplacements(character.Square);
                if (replacements.Squares.Count > 0 && replacements.Squares.Any(f => f.Square.HasWarrior))
                {

                    SelectionManager.AddSelectionOptions(
                         player,
                         SelectionType.Replacement,
                         replacements
                         );
                    return true;
                }
                
                if (BattleState.Rusher == character)
                    BattleState.IsAttackerPivotRequired = true;
                else
                    BattleState.IsDefenderPivotRequired = true;
               

                return false;
            }
            return false;
        }

        public void ClearDeadInBack()
        {
            foreach (var death in Arena.GetDeadCharacters(0))
            {
                death.Square.Character = null;
            }
            foreach (var death in Arena.GetDeadCharacters(3))
            {
                death.Square.Character = null;
            }

        }

        private void StartNewTurn()
        {
            BattleState.Rusher.DiscardUsedEffects();
            BattleState.RushTarget.DiscardUsedEffects();


            foreach (var row in Arena.Squares)
            {
                foreach (var square in row)
                {
                    if (square.HasWarrior)
                        square.Character.ApplyNewEffects();
                }
            }

            if (BattleState.IsAttackerPivotRequired)
                Arena.Pivot(BattleState.OtherPlayer);
            if (BattleState.IsDefenderPivotRequired)
                Arena.Pivot(BattleState.CurrentPlayer);
            BattleState.StartNewAttack();
             SelectionManager.ClearAll();
            SelectionManager.AddSelectionOptions(
                BattleState.CurrentPlayer,
                SelectionType.Rusher,
                SetupManager.GetAttackRows(BattleState.CurrentPlayer));
        }
    }

}
